﻿using System;
using System.Runtime.InteropServices;
using System.Text;

public static class XChipUSB
{
    // 根据平台选择 DLL
    private const string DllName86 = "x86/XChipUSBGeneral.dll";
    private const string DllName64 = "x64/XChipUSBGeneral_x64.dll";

    /// <summary>
    /// 初始化 USB 设备。
    /// 该方法用于准备设备以进行后续的读写操作。
    /// </summary>
    [DllImport(DllName86, EntryPoint = "UsbIniDevice", CallingConvention = CallingConvention.Cdecl)]
    public static extern void UsbIniDevice86();

    [DllImport(DllName64, EntryPoint = "UsbIniDevice", CallingConvention = CallingConvention.Cdecl)]
    public static extern void UsbIniDevice64();

    /// <summary>
    /// 更新 USB 设备。
    /// 该方法用于更新设备的固件或配置。
    /// </summary>
    /// <returns>如果成功，返回 true；否则返回 false。</returns>
    [DllImport(DllName86, EntryPoint = "UsbUpdateDevice", CallingConvention = CallingConvention.Cdecl)]
    public static extern bool UsbUpdateDevice86();

    [DllImport(DllName64, EntryPoint = "UsbUpdateDevice", CallingConvention = CallingConvention.Cdecl)]
    public static extern bool UsbUpdateDevice64();

    /// <summary>
    /// 从指定地址读取数据。
    /// 该方法用于读取存储在指定地址的数据。
    /// </summary>
    /// <param name="addr">要读取的地址。</param>
    /// <param name="pValue">读取的数据值（输出参数）。</param>
    /// <returns>如果成功，返回 true；否则返回 false。</returns>
    [DllImport(DllName86, EntryPoint = "UsbFlashRead", CallingConvention = CallingConvention.Cdecl)]
    public static extern bool UsbFlashRead86(uint addr, out uint pValue);

    [DllImport(DllName64, EntryPoint = "UsbFlashRead", CallingConvention = CallingConvention.Cdecl)]
    public static extern bool UsbFlashRead64(uint addr, out uint pValue);

    /// <summary>
    /// 向指定地址写入数据。
    /// 该方法用于将数据写入指定的地址。
    /// </summary>
    /// <param name="addr">要写入的地址。</param>
    /// <param name="value">要写入的数据值。</param>
    /// <returns>如果成功，返回 true；否则返回 false。</returns>
    [DllImport(DllName86, EntryPoint = "UsbFlashWrite", CallingConvention = CallingConvention.Cdecl)]
    public static extern bool UsbFlashWrite86(uint addr, uint value);

    [DllImport(DllName64, EntryPoint = "UsbFlashWrite", CallingConvention = CallingConvention.Cdecl)]
    public static extern bool UsbFlashWrite64(uint addr, uint value);

    /// <summary>
    /// 从设备批量读取数据。
    /// 该方法用于从设备中读取一段连续的数据。
    /// </summary>
    /// <param name="addr">开始读取的地址。</param>
    /// <param name="pBuff">用于存储读取数据的缓冲区。</param>
    /// <param name="length">要读取的数据长度。</param>
    /// <returns>如果成功，返回 true；否则返回 false。</returns>
    [DllImport(DllName86, EntryPoint = "UsbFlashBulkRead", CallingConvention = CallingConvention.Cdecl)]
    public static extern bool UsbFlashBulkRead86(uint addr, byte[] pBuff, uint length);

    [DllImport(DllName64, EntryPoint = "UsbFlashBulkRead", CallingConvention = CallingConvention.Cdecl)]
    public static extern bool UsbFlashBulkRead64(uint addr, byte[] pBuff, uint length);

    /// <summary>
    /// 向设备批量写入数据。
    /// 该方法用于将一段连续的数据写入设备的指定地址。
    /// </summary>
    /// <param name="addr">开始写入的地址。</param>
    /// <param name="pBuff">要写入的数据缓冲区。</param>
    /// <param name="length">要写入的数据长度。</param>
    /// <returns>如果成功，返回 true；否则返回 false。</returns>
    [DllImport(DllName86, EntryPoint = "UsbFlashBulkWrite", CallingConvention = CallingConvention.Cdecl)]
    public static extern bool UsbFlashBulkWrite86(uint addr, byte[] pBuff, uint length);

    [DllImport(DllName64, EntryPoint = "UsbFlashBulkWrite", CallingConvention = CallingConvention.Cdecl)]
    public static extern bool UsbFlashBulkWrite64(uint addr, byte[] pBuff, uint length);

    /// <summary>
    /// 从 I2C 设备读取数据。
    /// 该方法用于从指定的 I2C 设备读取数据。
    /// </summary>
    /// <param name="id">I2C 设备的 ID。</param>
    /// <param name="addr">设备地址。</param>
    /// <param name="pValue">读取的数据值（输出参数）。</param>
    /// <param name="type">读取类型的标识，可能影响读取的方式。</param>
    /// <param name="waitType">等待类型，影响读取操作的等待策略。</param>
    /// <returns>如果成功，返回 true；否则返回 false。</returns>
    [DllImport(DllName86, EntryPoint = "UsbI2cRead", CallingConvention = CallingConvention.Cdecl)]
    public static extern bool UsbI2cRead86(uint id, uint addr, out uint pValue, int type, int waitType);

    [DllImport(DllName64, EntryPoint = "UsbI2cRead", CallingConvention = CallingConvention.Cdecl)]
    public static extern bool UsbI2cRead64(uint id, uint addr, out uint pValue, int type, int waitType);

    /// <summary>
    /// 向 I2C 设备写入数据。
    /// 该方法用于将数据写入指定的 I2C 设备。
    /// </summary>
    /// <param name="id">I2C 设备的 ID。</param>
    /// <param name="addr">设备地址。</param>
    /// <param name="pValue">要写入的数据值。</param>
    /// <param name="type">写入类型的标识，可能影响写入的方式。</param>
    /// <param name="waitType">等待类型，影响写入操作的等待策略。</param>
    /// <returns>如果成功，返回 true；否则返回 false。</returns>
    [DllImport(DllName86, EntryPoint = "UsbI2cWrite", CallingConvention = CallingConvention.Cdecl)]
    public static extern bool UsbI2cWrite86(uint id, uint addr, uint pValue, int type, int waitType);

    [DllImport(DllName64, EntryPoint = "UsbI2cWrite", CallingConvention = CallingConvention.Cdecl)]
    public static extern bool UsbI2cWrite64(uint id, uint addr, uint pValue, int type, int waitType);

    /// <summary>
    /// 获取固件版本信息。
    /// 该方法用于获取设备的固件版本信息，并存储在提供的缓冲区中。
    /// </summary>
    /// <param name="buffer">用于存储版本信息的缓冲区。</param>
    /// <param name="bufferSize">缓冲区大小（输入/输出参数）。</param>
    /// <returns>如果成功，返回 true；否则返回 false。</returns>
    [DllImport(DllName86, EntryPoint = "UsbGetFirmwareVersionInfo", CallingConvention = CallingConvention.Cdecl)]
    public static extern bool UsbGetFirmwareVersionInfo86([MarshalAs(UnmanagedType.LPStr)] StringBuilder buffer, ref uint bufferSize);

    [DllImport(DllName64, EntryPoint = "UsbGetFirmwareVersionInfo", CallingConvention = CallingConvention.Cdecl)]
    public static extern bool UsbGetFirmwareVersionInfo64([MarshalAs(UnmanagedType.LPStr)] StringBuilder buffer, ref uint bufferSize);

    /// <summary>
    /// 获取所有 USB 设备的信息。
    /// 该方法用于获取连接的所有 USB 设备的相关信息。
    /// </summary>
    /// <param name="deviceList">存储设备信息的数组。</param>
    /// <param name="num">设备数量（输入/输出参数）。</param>
    /// <returns>如果成功，返回 true；否则返回 false。</returns>
    [DllImport(DllName86, EntryPoint = "UsbGetAllDeviceInfo", CallingConvention = CallingConvention.Cdecl)]
    public static extern bool UsbGetAllDeviceInfo86(DeviceInfos[] deviceList, ref uint num);

    [DllImport(DllName64, EntryPoint = "UsbGetAllDeviceInfo", CallingConvention = CallingConvention.Cdecl)]
    public static extern bool UsbGetAllDeviceInfo64(DeviceInfos[] deviceList, ref uint num);


    /// <summary>
    /// 从多路复用接口获取所有 USB 设备的信息。
    /// </summary>
    /// <returns>指向设备信息结构的指针。</returns>
    [DllImport(DllName64, EntryPoint = "UsbGetAllDeviceInfo_MultiplexInterface", CallingConvention = CallingConvention.Cdecl)]
    public static extern IntPtr UsbGetAllDeviceInfo_MultiplexInterface64();

    [DllImport(DllName86, EntryPoint = "UsbGetAllDeviceInfo_MultiplexInterface", CallingConvention = CallingConvention.Cdecl)]
    public static extern IntPtr UsbGetAllDeviceInfo_MultiplexInterface86();


    /// <summary>
    /// 获取连接的 USB 设备数量。
    /// </summary>
    /// <returns>返回设备数量。如果出错，返回 -1。</returns>
    [DllImport(DllName86, EntryPoint = "UsbGetDeviceNum", CallingConvention = CallingConvention.Cdecl)]
    public static extern int UsbGetDeviceNum86();

    [DllImport(DllName64, EntryPoint = "UsbGetDeviceNum", CallingConvention = CallingConvention.Cdecl)]
    public static extern int UsbGetDeviceNum64();

    /// <summary>
    /// 向 I2C 设备批量写入数据。
    /// 该方法用于将一段连续的数据写入指定的 I2C 设备。
    /// </summary>
    /// <param name="start_address">开始写入的地址。</param>
    /// <param name="array">要写入的数据数组（指针）。</param>
    /// <param name="array_size">数组的大小。</param>
    /// <param name="ID">I2C 设备的 ID。</param>
    /// <returns>如果成功，返回 true；否则返回 false。</returns>
    [DllImport(DllName86, EntryPoint = "UsbI2CBulkWrite", CallingConvention = CallingConvention.Cdecl)]
    public static extern bool UsbI2CBulkWrite86(uint start_address, uint[] array, uint array_size, uint ID);

    [DllImport(DllName64, EntryPoint = "UsbI2CBulkWrite", CallingConvention = CallingConvention.Cdecl)]
    public static extern bool UsbI2CBulkWrite64(uint start_address, uint[] array, uint array_size, uint ID);



    /// <summary>
    /// 从 I2C 设备批量读取数据（32位）。
    /// </summary>
    /// <param name="start_address">开始读取的地址。</param>
    /// <param name="array">存储读取数据的数组（指针）。</param>
    /// <param name="array_size">数组的大小。</param>
    /// <param name="ID">I2C 设备的 ID。</param>
    /// <returns>如果成功，返回 true；否则返回 false。</returns>
    [DllImport(DllName86, EntryPoint = "UsbI2CBulkRead", CallingConvention = CallingConvention.Cdecl)]
    public static extern bool UsbI2CBulkRead86(uint start_address, uint[] array, uint array_size, uint ID);

    /// <summary>
    /// 从 I2C 设备批量读取数据（64位）。
    /// </summary>
    /// <param name="start_address">开始读取的地址。</param>
    /// <param name="array">存储读取数据的数组（指针）。</param>
    /// <param name="array_size">数组的大小。</param>
    /// <param name="ID">I2C 设备的 ID。</param>
    /// <returns>如果成功，返回 true；否则返回 false。</returns>
    [DllImport(DllName64, EntryPoint = "UsbI2CBulkRead", CallingConvention = CallingConvention.Cdecl)]
    public static extern bool UsbI2CBulkRead64(uint start_address, uint[] array, uint array_size, uint ID);


    /// <summary>
    /// 销毁 USB 设备资源。
    /// </summary>
    /// <returns>如果成功释放资源返回 true；否则返回 false。</returns>
    [DllImport(DllName86, EntryPoint = "UsbDestroyUSB", CallingConvention = CallingConvention.Cdecl)]
    public static extern bool UsbDestroyUSB86();

    /// <summary>
    /// 销毁 USB 设备资源（64位）。
    /// </summary>
    /// <returns>如果成功释放资源返回 true；否则返回 false。</returns>
    [DllImport(DllName64, EntryPoint = "UsbDestroyUSB", CallingConvention = CallingConvention.Cdecl)]
    public static extern bool UsbDestroyUSB64();

    // 包装函数以选择合适的 DLL
    /// <summary>
    /// 包装方法，选择合适的 DLL 进行设备初始化。
    /// </summary>
    public static void UsbIniDevice()
    {
        if (Environment.Is64BitProcess)
        {
            UsbIniDevice64();
        }
        else
        {
            UsbIniDevice86();
        }
    }

    /// <summary>
    /// 包装方法，选择合适的 DLL 进行设备更新。
    /// </summary>
    /// <returns>如果成功，返回 true；否则返回 false。</returns>
    public static bool UsbUpdateDevice()
    {
        return Environment.Is64BitProcess ? UsbUpdateDevice64() : UsbUpdateDevice86();
    }

    /// <summary>
    /// 包装方法，选择合适的 DLL 从指定地址读取数据。
    /// </summary>
    /// <param name="addr">要读取的地址。</param>
    /// <param name="pValue">读取的数据值（输出参数）。</param>
    /// <returns>如果成功，返回 true；否则返回 false。</returns>
    public static bool UsbFlashRead(uint addr, out uint pValue)
    {
        return Environment.Is64BitProcess ? UsbFlashRead64(addr, out pValue) : UsbFlashRead86(addr, out pValue);
    }

    /// <summary>
    /// 包装方法，选择合适的 DLL 向指定地址写入数据。
    /// </summary>
    /// <param name="addr">要写入的地址。</param>
    /// <param name="value">要写入的数据值。</param>
    /// <returns>如果成功，返回 true；否则返回 false。</returns>
    public static bool UsbFlashWrite(uint addr, uint value)
    {
        return Environment.Is64BitProcess ? UsbFlashWrite64(addr, value) : UsbFlashWrite86(addr, value);
    }

    /// <summary>
    /// 包装方法，选择合适的 DLL 获取连接的 USB 设备数量。
    /// </summary>
    /// <returns>返回设备数量。如果出错，返回 -1。</returns>
    public static int UsbGetDeviceNum()
    {
        return Environment.Is64BitProcess ? UsbGetDeviceNum64() : UsbGetDeviceNum86();
    }

    /// <summary>
    /// 包装方法，选择合适的 DLL 批量读取数据。
    /// </summary>
    /// <param name="addr">开始读取的地址。</param>
    /// <param name="pBuff">用于存储读取数据的缓冲区。</param>
    /// <param name="length">要读取的数据长度。</param>
    /// <returns>如果成功，返回 true；否则返回 false。</returns>
    public static bool UsbFlashBulkRead(uint addr, byte[] pBuff, uint length)
    {
        return Environment.Is64BitProcess ? UsbFlashBulkRead64(addr, pBuff, length) : UsbFlashBulkRead86(addr, pBuff, length);
    }

    /// <summary>
    /// 包装方法，选择合适的 DLL 批量写入数据。
    /// </summary>
    /// <param name="addr">开始写入的地址。</param>
    /// <param name="pBuff">要写入的数据缓冲区。</param>
    /// <param name="length">要写入的数据长度。</param>
    /// <returns>如果成功，返回 true；否则返回 false。</returns>
    public static bool UsbFlashBulkWrite(uint addr, byte[] pBuff, uint length)
    {
        return Environment.Is64BitProcess ? UsbFlashBulkWrite64(addr, pBuff, length) : UsbFlashBulkWrite86(addr, pBuff, length);
    }

    /// <summary>
    /// 包装方法，选择合适的 DLL 从 I2C 设备读取数据。
    /// </summary>
    /// <param name="id">I2C 设备的 ID。</param>
    /// <param name="addr">设备地址。</param>
    /// <param name="pValue">读取的数据值（输出参数）。</param>
    /// <param name="type">读取类型的标识，可能影响读取的方式。</param>
    /// <param name="waitType">等待类型，影响读取操作的等待策略。</param>
    /// <returns>如果成功，返回 true；否则返回 false。</returns>
    public static bool UsbI2cRead(uint id, uint addr, out uint pValue, int type, int waitType)
    {
        return Environment.Is64BitProcess ? UsbI2cRead64(id, addr, out pValue, type, waitType) : UsbI2cRead86(id, addr, out pValue, type, waitType);
    }

    /// <summary>
    /// 包装方法，选择合适的 DLL 向 I2C 设备写入数据。
    /// </summary>
    /// <param name="id">I2C 设备的 ID。</param>
    /// <param name="addr">设备地址。</param>
    /// <param name="pValue">要写入的数据值。</param>
    /// <param name="type">写入类型的标识，可能影响写入的方式。</param>
    /// <param name="waitType">等待类型，影响写入操作的等待策略。</param>
    /// <returns>如果成功，返回 true；否则返回 false。</returns>
    public static bool UsbI2cWrite(uint id, uint addr, uint pValue, int type, int waitType)
    {
        return Environment.Is64BitProcess ? UsbI2cWrite64(id, addr, pValue, type, waitType) : UsbI2cWrite86(id, addr, pValue, type, waitType);
    }

    /// <summary>
    /// 包装方法，选择合适的 DLL 获取固件版本信息。
    /// </summary>
    /// <param name="buffer">用于存储版本信息的缓冲区。</param>
    /// <param name="bufferSize">缓冲区大小（输入/输出参数）。</param>
    /// <returns>如果成功，返回 true；否则返回 false。</returns>
    public static bool UsbGetFirmwareVersionInfo(StringBuilder buffer, ref uint bufferSize)
    {
        return Environment.Is64BitProcess ? UsbGetFirmwareVersionInfo64(buffer, ref bufferSize) : UsbGetFirmwareVersionInfo86(buffer, ref bufferSize);
    }

    /// <summary>
    /// 包装方法，选择合适的 DLL 获取所有 USB 设备的信息。
    /// </summary>
    /// <param name="deviceList">存储设备信息的数组。</param>
    /// <param name="num">设备数量（输入/输出参数）。</param>
    /// <returns>如果成功，返回 true；否则返回 false。</returns>
    public static bool UsbGetAllDeviceInfo(DeviceInfos[] deviceList, ref uint num)
    {
        return Environment.Is64BitProcess ? UsbGetAllDeviceInfo64(deviceList, ref num) : UsbGetAllDeviceInfo86(deviceList, ref num);
    }

    /// <summary>
    /// 从多路复用接口获取所有 USB 设备的信息。
    /// </summary>
    /// <param name="num">设备数量。</param>
    /// <returns>包含设备信息的数组。如果失败则返回空数组。</returns>
    public static DeviceInfos[] UsbGetAllDeviceInfoViaMultiplex(int num)
    {
        IntPtr devicePtr = Environment.Is64BitProcess ? UsbGetAllDeviceInfo_MultiplexInterface64() : UsbGetAllDeviceInfo_MultiplexInterface86(); // 获取设备信息的指针
        DeviceInfos[] deviceList = new DeviceInfos[num];

        if (devicePtr == IntPtr.Zero)
        {
            return new DeviceInfos[0]; // 获取设备信息失败，返回空数组
        }

        // 填充设备信息
        for (int i = 0; i < num; i++)
        {
            DeviceInfos deviceInfo = new DeviceInfos();
            var one = (i * 120) * 2 + (i * 8);
            deviceInfo.DevicePath = Marshal.PtrToStringAnsi(devicePtr + one, 120);
            var two = (i * 120) * 2 + 120 + (i * 8);
            deviceInfo.DeviceName = Marshal.PtrToStringAnsi(devicePtr + two, 120);
            var three = (i * 120) * 2 + 240 + (i * 8);
            deviceInfo.PID = Marshal.PtrToStringAnsi(devicePtr + three, 4); // 读取内存中的 uint 值  
            var four = (i * 120) * 2 + 240 + 4 + (i * 8);
            deviceInfo.VID = Marshal.PtrToStringAnsi(devicePtr + four, 4); // 读取内存中的 uint 值  
            
            deviceList[i] = deviceInfo; // 将复制的数据添加到数组中
        }

        return deviceList; // 返回设备信息数组
    }


    /// <summary>
    /// 包装方法，选择合适的 DLL 向 I2C 设备批量写入数据。
    /// </summary>
    /// <param name="start_address">开始写入的地址。</param>
    /// <param name="array">要写入的数据数组。</param>
    /// <param name="array_size">数组的大小。</param>
    /// <param name="ID">I2C 设备的 ID。</param>
    /// <returns>如果成功，返回 true；否则返回 false。</returns>
    public static bool UsbI2CBulkWrite(uint start_address, uint[] array, uint array_size, uint ID)
    {
        return Environment.Is64BitProcess ? UsbI2CBulkWrite64(start_address, array, array_size, ID) : UsbI2CBulkWrite86(start_address, array, array_size, ID);
    }

    /// <summary>
    /// 从 I2C 设备批量读取数据。
    /// </summary>
    /// <param name="start_address">开始读取的地址。</param>
    /// <param name="array">存储读取数据的数组。</param>
    /// <param name="array_size">数组的大小。</param>
    /// <param name="ID">I2C 设备的 ID。</param>
    /// <returns>如果成功，返回 true；否则返回 false。</returns>
    public static bool UsbI2CBulkRead(uint start_address, uint[] array, uint array_size, uint ID)
    {
        return Environment.Is64BitProcess ? UsbI2CBulkRead64(start_address, array, array_size, ID) : UsbI2CBulkRead86(start_address, array, array_size, ID);
    }


    /// <summary>
    /// 销毁 USB 设备资源。
    /// </summary>
    /// <returns>如果成功释放资源返回 true；否则返回 false。</returns>
    public static bool UsbDestroyUSB()
    {
        return Environment.Is64BitProcess ? UsbDestroyUSB64() : UsbDestroyUSB86();
    }
    /// <summary>
    /// 选择 USB 设备。
    /// </summary>
    /// <param name="index">要选择的设备索引。</param>
    /// <returns>如果成功，返回 true；否则返回 false。</returns>
    [DllImport(DllName86, EntryPoint = "UsbSelectDevice", CallingConvention = CallingConvention.Cdecl)]
    public static extern bool UsbSelectDevice86(int index);

    [DllImport(DllName64, EntryPoint = "UsbSelectDevice", CallingConvention = CallingConvention.Cdecl)]
    public static extern bool UsbSelectDevice64(int index);

    /// <summary>
    /// 选择 USB 设备（根据系统架构选择适当的方法）。
    /// </summary>
    /// <param name="index">要选择的设备索引。</param>
    /// <returns>如果成功，返回 true；否则返回 false。</returns>
    public static bool UsbSelectDevice(int index)
    {
        return Environment.Is64BitProcess ? UsbSelectDevice64(index) : UsbSelectDevice86(index);
    }


}

/// <summary>
/// 设备信息结构体，用于存储 USB 设备的相关信息。
/// </summary>
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct DeviceInfos
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 120)]
    public string DevicePath;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 120)]
    public string DeviceName;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 4)]
    public string PID;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 4)]
    public string VID;
}
